/*******************************************************************
    format		c type
    ---------------------
    x/X			pad byte
    c/b			s8/u8/char
    h			s16/u16
    i			s32/u32
    l			s64/u64
    f			float
    d			double
    ----------------------
    s/S			pointer of char, end with \0
    B			pointer of s8/u8
    H			pointer of s16/u16
    I			pointer of s32/u32
    L			pointer of s64/u64
    F			pointer of float
    D			pointer of double
    ----------------------
    endian
    ----------------------
    >	big endian
    <   little endian
    !   host endian
*********************************************************************/

#ifndef __STRUCT_UTIL_H
#define __STRUCT_UTIL_H
#include <stdint.h>
#include "endian.h"
#ifdef __cplusplus
extern "C"
{
#endif

#define STRUCT_UTIL_UNKNOW_SEQUENCE -1

#define U64_DATA(PTR) (*(uint64_t *)(PTR))
#define U32_DATA(PTR) (*(uint32_t *)(PTR))
#define U16_DATA(PTR) (*(uint16_t *)(PTR))
#define U8_DATA(PTR) (*(uint8_t *)(PTR))
#define S64_DATA(PTR) (*(int64_t *)(PTR))
#define S32_DATA(PTR) (*(int32_t *)(PTR))
#define S16_DATA(PTR) (*(int16_t *)(PTR))
#define S8_DATA(PTR) (*(int8_t *)(PTR))

/* 从一段内存地址以相应的字节序取出一个数据，返回值为主机字节序，可直接使用 */
#define FROM_BE16(PTR) (be16toh(U16_DATA(PTR)))
#define FROM_BE32(PTR) (be32toh(U32_DATA(PTR)))
#define FROM_LE16(PTR) (le16toh(U16_DATA(PTR)))
#define FROM_LE32(PTR) (le32toh(U32_DATA(PTR)))

#define FROM_LEFP32(PTR) h32_to_fp32(htole32(U32_DATA(PTR)))
#define FROM_BEFP32(PTR) h32_to_fp32(htobe32(U32_DATA(PTR)))
    // #define FROM_LWFP32(PTR) h32_to_fp32(htole32(U32_DATA(PTR)))
    // #define FROM_BWFP32(PTR) h32_to_fp32(htobw32(U32_DATA(PTR)))

#define TO_BE16(PTR, DATA) U16_DATA(PTR) = htobe16(DATA)
#define TO_BE32(PTR, DATA) U32_DATA(PTR) = htobe32(DATA)
#define TO_LE16(PTR, DATA) U16_DATA(PTR) = htole16(DATA)
#define TO_LE32(PTR, DATA) U32_DATA(PTR) = htole32(DATA)
#define TO_BEFP32(PTR, DATA) U32_DATA(PTR) = htobe32(fp32_to_h32((DATA)))
#define TO_LEFP32(PTR, DATA) U32_DATA(PTR) = htole32(fp32_to_h32((DATA)))

#if (__BYTE_ORDER_HOST == __BYTE_ORDER_BIG)
#define htobe32_inplace(dataptr, datalen)
#define htobe16_inplace(dataptr, datalen)
#define htole32_inplace(dataptr, datalen) bswap32_inplace(dataptr, datalen)
#define htole16_inplace(dataptr, datalen) bswap16_inplace(dataptr, datalen)
#define be32toh_inplace(dataptr, datalen)
#define be16toh_inplace(dataptr, datalen)
#define le32toh_inplace(dataptr, datalen) bswap32_inplace(dataptr, datalen)
#define le16toh_inplace(dataptr, datalen) bswap16_inplace(dataptr, datalen)

#elif (__BYTE_ORDER_HOST == __BYTE_ORDER_LITTLE)
#define htobe32_inplace(dataptr, datalen) bswap32_inplace((void*)dataptr, datalen)
#define htobe16_inplace(dataptr, datalen) bswap16_inplace((void*)dataptr, datalen)
#define htole32_inplace(dataptr, datalen)
#define htole16_inplace(dataptr, datalen)
#define be32toh_inplace(dataptr, datalen) bswap32_inplace((void*)dataptr, datalen)
#define be16toh_inplace(dataptr, datalen) bswap16_inplace((void*)dataptr, datalen)
#define le32toh_inplace(dataptr, datalen)
#define le16toh_inplace(dataptr, datalen)

#endif

    uint32_t fp32_to_h32(float __fp32);
    uint64_t fp64_to_h64(double __fp64);
    float h32_to_fp32(uint32_t __u32);
    double h64_to_fp64(uint64_t __u64);
    int bswap16_inplace(uint16_t *dataptr, int datalen);
    int bswap32_inplace(uint32_t *dataptr, int datalen);

    int struct_util_pack(uint8_t *buffer, const char *format, ...);
    int struct_util_unpack(const uint8_t *buffer, const char *format, ...);

#ifdef __cplusplus
}
#endif
#endif // __STRUCT_UTIL_H
